var express = require('express');
const { writeFile, mkdir, readdir, readFile, appendFile, unlink } = require('fs/promises');
var router = express.Router();
const path = require('path')
const sparkMD5 = require('spark-md5')
const multiparty = require('multiparty');


const upload_multy = require('../config/multer').upload_multy
const dir_multy = require('../config/multer').dir_multy

const upload_chunk = require('../config/multer').upload_chunk

/* GET home page. */
router.get('/', function (req, res, next) {
  res.render('index', { title: 'express' });
});

router.post('/', function (req, res, next) {

  // 找到每次我上传的原因了, 如果nodejs用Promise的异步响应, 就会引发前端的页面刷新, 而同步则不会
  // Promise.resolve(res.send(req.body))

  res.send(req.body);
});

// 注意post的跨域要在app.all里面配置

// 注意: 如果不处理错误,就可以这么写,但是如果需要处理错误,就必须使用下面的写法
router.post('/upload_form', upload_multy.array('files'), function (req, res) {
  console.dir(req.files)
  console.log(req.body)
  res.send({
    ok: 1,
    servePath: path.join('http://127.0.0.1:3000', dir_multy)
  })
})


function parseReq(req) {
  return new Promise((resolve, reject) => {
    let form = new multiparty.Form({
      uploadDir: dir_multy,
      maxFilesSize: 1248 * 1024 * 1024
    })

    form.parse(req, (err, fields, files) => {
      if (err) reject(err)
      resolve({
        fields,
        files
      })
    })
  })
}

// 处理错误, 接收multer返回的函数
let upload_multy_ = upload_multy.array('files')

// 在响应的回调函数内部使用multer返回的函数即upload_multy_
// 第三个参数是错误处理的函数,直接在里面写处理就好了,如果没有错误正常处理即可
router.post('/upload_formdata', async function (req, res) {

  try {
    let { files } = await parseReq(req)
    console.log(files)
    res.send({
      ok: 1,
      info: files.files.map(item => {
        console.log(path.join('http://127.0.0.1:3000', item.path.replace('tmp\\\\', '')))
        return path.join('http://127.0.0.1:3000', item.path.replace('tmp', ''))
      })
    })
  }
  catch (e) {
    res.send({
      ok: 0,
      info: e
    })
  }

  // await upload_multy_(req, res, function (err) {
  //   if (err) {
  //     res.send({
  //       ok: 0,
  //       info: err
  //     })
  //   }
  //   // Everything went fine.
  //   else {
  //     console.dir(req.files)
  //     console.log(req.body)
  //     res.send({
  //       ok: 1,
  //       info: req.files.map(item => path.join('http://127.0.0.1:3000', `my-uploads/${item.filename}`))
  //     })
  //   }

  // })

})

router.post('/upload_base64', async function (req, res) {
  // base64使用表单好像有些问题
  // 主要还是不会直接接收FormData的格式

  let filesPromises = []

  req.body.files.forEach((item, index, arr) => {
    let file = Buffer.from(decodeURIComponent(item.result).replace(/^data:image\/\w+;base64,/, ""), 'base64url')
    // console.log(file)
    let spark = new sparkMD5.ArrayBuffer()
    spark.append(file)
    // console.log(spark.end())
    arr[index].filename = `${dir_multy}/${spark.end().substring(0, 9)}${item.name.match(/\.([^\.]*)$/)[0]}`
    filesPromises.push(
      writeFile(arr[index].filename, file)
    )

  })

  // Promise.all(filesPromises).then(() => {
  //   res.send({
  //     ok: 1,
  //     info: req.body.files.map(item => path.join('http://127.0.0.1:3000', `${item.filename}`.replace('tmp/', '')))
  //   })
  // }).catch(e => {
  //   res.send({
  //     ok: 0,
  //     info: e
  //   })
  // })

  // 怎么解决异步响应导致前端刷新的问题呢
  try {
    await Promise.all(filesPromises)
    res.send({
      ok: 1,
      info: req.body.files.map(item => path.join('http://127.0.0.1:3000', `${item.filename}`.replace('tmp/', '')))
    })
  }
  catch (e) {
    res.send({
      ok: 0,
      info: e
    })
  }


})


const fs = require('fs');

// 解析获得form表单的文件和非文件信息
function getContent(req, form) {
  return new Promise((resolve, reject) => {
    form.parse(req, (err, fields, files) => {
      if (err) {
        reject(err)
      }
      resolve({
        fields,
        files
      })
    })
  })
}

router.post('/upload_chunk', async (req, res) => {


  // nodejs后端没有FileReader()，所以不能使用整个webAPI转Buffer
  // let reader = new FileReader()
  // reader.readAsArrayBuffer(files.file[0])

  // reader.onloadend(ev => {  ev.target.result  }
  // --------------------------------

  // 第一种： 直接先把文件存进来再重命名（根据切片的序号重命名），但是如果很多用户同时存储，目录不变化，
  // 但是服务器只有一个，那都存进一个目录内，不好合并，文件杂乱而多
  // 所以有一种方法就是先让前端发一个token过来，以此解密用户名+文件名来创建目录（用户名唯一），否则就不行
  // 但是这样会浪费一个请求
  // const form = new multiparty.Form({ uploadDir: dir_multy })

  // ------------------------------这里直接就是通过parse解析也可以直接获得结果，如下
  // 这里
  const form = new multiparty.Form({
    maxFilesSize: 300 * 1024 * 1024
  })
  let { fields, files } = await getContent(req, form)

  // console.log(fields)
  // console.log(files)

  let dir = `tmp/${fields.filename[0]}`

  // 如果目录不存在才会创建
  if (!fs.existsSync(dir)) {
    try {
      await mkdir(dir)
    }
    catch (e) {
      console.log(e)
      res.send({
        ok: 0,
        info: e
      })
    }
  }

  // 写入文件
  try {
    // 对于文件直接用流读写就行了，服务器接收到分割的blob文件会存在files.file[0].path内
    // 读出文件再写一个文件出来就行了
    let readStream = fs.createReadStream(files.file[0].path)
    let writeStream = fs.createWriteStream(`${dir}/${fields.index[0]}`)
    readStream.pipe(writeStream)

    readStream.on('end', () => {

      // 此时已经文件写入完毕，成功了  
      res.send({
        ok: 1,
        info: 'upload success',
      });

      // 删除服务器缓存的文件，已经存了就删掉
      unlink(files.file[0].path).catch(e => {
        console.log(e)
        throw e
      });

    });

    readStream.on('error', (err) => {
      console.log(err)
      throw err
    })
  }
  catch (e) {
    res.send({
      ok: 0,
      info: e
    })
  }


})


router.post('/chunk_merge', (req, res) => {
  console.log(req.body)
  let filename = req.body.filename
  let dir = path.resolve(__dirname, `../tmp/${filename}`)

  try {
    let fileList = fs.readdirSync(dir)
    // 获得文件名字
    console.log(fileList)
    let mainFilePath = `${dir}/${filename}`
    fileList.sort((a, b) => a - b).forEach(async (item) => {
      let appendFilePath = `${dir}/${item}`
      console.log(appendFilePath)
      let file = fs.readFileSync(appendFilePath, err => { console.log(err) })
      console.log('read' + appendFilePath)
      fs.appendFileSync(mainFilePath, file)
      console.log('append' + appendFilePath)
      unlink(appendFilePath).catch(e => {console.log(e)})
    })

    res.send({
      ok: 1,
      info: 'merged'
    })

  }
  catch (e) {
    console.log(e)
    res.send({
      ok: 0,
      info: e
    })
  }
})

// 合并的前期是前端发，才好返回响应告诉前端是否合成成功了

async function mergeChunks(res, dir) {


}


module.exports = router;
